package Negocio;

import Negocio.Cola.Contenedor;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import javax.swing.JOptionPane;

/**
 *
 * @author
 */
public class EscaladaSimple extends MetodoBusqueda {

    private Contenedor<Hoja> abierto;
    private Hoja m;

    public EscaladaSimple() {
        abierto = new Contenedor<Hoja>();
        m = null;
    }

    @Override
    public List<Estado> obtenerOptimo() {
        List<Estado> optimo = new ArrayList<Estado>();
        List<Hoja> camino = arbol.getCaminoOptimo();

        for (int i = 0; i < camino.size(); i++) {
            optimo.add(camino.get(i).getEstado());
        }
        return optimo;
    }

//    @Override
    public void procesar() {
        boolean tieneHijosMejores = false;
        Hoja mejorTemporal;
        iniciarArbol();
        boolean fin = false;
        Hoja raiz = arbol.getRaiz();
        List<Hoja> optimo = new ArrayList<Hoja>();
        List<Hoja> optimo2 = new ArrayList<Hoja>();
        Hoja hojaActual = raiz;
        List<Hoja> hojasIndeseables = new ArrayList<Hoja>();

        if (raiz.esEstadoFinal()) {
            hojaActual.setEsCamino(true);
            optimo.add(0,hojaActual);
            arbol.setCaminoOptimo(optimo);
            return;
        } else {
            //**
            hojaActual.setEsCamino(true);
            optimo2.add(hojaActual);
            List<Hoja> hijos = null;
            List<Hoja> hermanos = null;
            while (!fin) {
                if(hermanos != null){
                    if(hermanos.isEmpty()){

                    }else{
                        arbol.cargarHijosDinamico(hojaActual);
                        hijos = hojaActual.getHijos();
                    }
                }else{
                    arbol.cargarHijosDinamico(hojaActual);
                    hijos = hojaActual.getHijos();
                }

                if (hijos == null) {
                    fin = true;
                    break;
                }
                if (hijos.isEmpty()) {
                    if(!hojasIndeseables.contains(hojaActual)){
                        hojasIndeseables.add(hojaActual);
                    }
                    if(hojaActual.esEstadoFinal()){
                        break;
                    }else{
                        Hoja padreTemporal = hojaActual.getPadre();
                        while(hojasIndeseables.contains(padreTemporal)){
                            padreTemporal = padreTemporal.getPadre();
                        }
                        arbol.cargarHijosDinamico(padreTemporal);
                        hermanos = padreTemporal.getHijos();
                        if(!hermanos.isEmpty()){
                            for(int n = 0 ; n < hermanos.size() ; n++){
                                if(hermanos.get(n).equals(hojaActual)){
                                    if(!hojasIndeseables.contains(hermanos.get(n))){
                                        hojasIndeseables.add(hermanos.get(n));
                                    }
                                }
                            }

                            for(int h = 0 ; h < hermanos.size() ; h++){
                                if(!hojasIndeseables.isEmpty() && !hermanos.isEmpty()){
                                    if(hojasIndeseables.contains(hermanos.get(h))){
                                            hermanos.remove(h);
                                    }
                                }
                            }
                        }
                        //**
                        hojaActual.setEsCamino(true);
                        optimo2.add(hojaActual);
                        hojaActual = padreTemporal;
                        hijos = hermanos;
                    }
                }
                boolean otraBanderaMas = false;
                if(hijos.isEmpty()){
                    mejorTemporal = null;
                    otraBanderaMas = true;
                }else{
                    mejorTemporal = hijos.get(0);
                    tieneHijosMejores=false;
                }
                for (int i = 0; i < hijos.size(); i++) {
                    obtenerMetrica(hijos.get(i));
                    obtenerMetrica(hojaActual);
                    obtenerMetrica(mejorTemporal);

                    if (hijos.get(i).getEstado().getMetrica() < hojaActual.getEstado().getMetrica()) {

                        //**
                        hojaActual.setEsCamino(true);
                        optimo2.add(hojaActual);
                        hojaActual = hijos.get(i);
                        tieneHijosMejores = true;
                    }
                    if (mejorTemporal.getEstado().getMetrica()>hijos.get(i).getEstado().getMetrica()) {
                        mejorTemporal = hijos.get(i);
                    }
                    
                    if (hojaActual.esEstadoFinal()) {
                        fin = true;
                    }
                }
                if (!tieneHijosMejores) {
                    if(otraBanderaMas){

                    }else{
                        //**
                        hojaActual.setEsCamino(true);
                        optimo2.add(hojaActual);
                        hojaActual = mejorTemporal;
                    }
                }
            }
            optimo2.add(hojaActual);
//            while (hojaActual.getPadre() != null) {
//                hojaActual.setEsCamino(true);
//                optimo.add(0,hojaActual);
//                hojaActual = hojaActual.getPadre();
//            }
            hojaActual.setEsCamino(true);
//            optimo2.add(hojaActual);
        }
        arbol.setCaminoOptimo(optimo2);
    }
//
//    public void procesar(){
////      1. Denominar m al estado inicial y evaluarlo. Si es estado objetivo,
////      entonces devolverlo y terminar, si no, convertirlo en estado actual.
////      Asignar m a una varibla llamada elegido.
//
////      2. Repetir hasta que se encuentre solución o hasta que una
////      iteración completa no produzca un cambio en el estado actual:
//
////          2.1 Expandir m creando el conjunto de todos sus sucesores.
//
////              2.1.A. Aplicar cada operador aplicable al estado actual m y conseguir
////                 nuevos estados E1, ... En.
//
////              2.1.B. Evaluar E1 .... En. Si alguno es objetivo, devolverlo y terminar Si
////              no es así, seleccionar el mejor H(Em)
//
////              2.1.C. Si el mejor estado Em es mejor que el estado actual, hacer que
////              Em sea el estado actual. Volver al paso 2.
////**            Si no es así, buscar el padre del estado actual, calcular sus sucesores
////**            y eliminar de ellos a estado actual. Volver a a 2.1.B.
//
//
//
//        boolean tieneHijosMejores = true;
//        boolean raizSinHijosMejores = false;
//        iniciarArbol();
//
//        List<Hoja> optimo = new ArrayList<Hoja>();
//        Hoja raiz = arbol.getRaiz();
//        Hoja hojaActual = raiz;
//        Hoja mejorTemp = null;
//
//        List<Hoja> hojasAEvitar = new ArrayList<Hoja>();
//        boolean fin = false;
//        //1.
//        optimo.add(hojaActual);
//        if (raiz.esEstadoFinal()) {
//            hojaActual.setEsCamino(true);
//
//            arbol.setCaminoOptimo(optimo);
//            return;
//        } else {
//            while(true){
//                List<Hoja> hijos = null;
//                if(!tieneHijosMejores){
//                    if(hojaActual.getPadre() != null){
//                        //2.1.C.
//                        Hoja padre = hojaActual.getPadre();
//                        arbol.cargarHijosDinamico(padre);
//                        hijos = padre.getHijos();
////                        hijos.remove(hojaActual);
//                        if(!hojasAEvitar.contains(hojaActual)){
//                            hojasAEvitar.add(hojaActual);
//                        }
//                        hojaActual = padre;
//                        raizSinHijosMejores = false;
//                        verificarHijos(hojasAEvitar, hijos);
//                    }else{
//                        //2.1.A
//                        System.out.println("cansadooooooooooooooooooooooooo");
//                        arbol.cargarHijosDinamico(hojaActual);
//                        hijos = hojaActual.getHijos();
//                        raizSinHijosMejores = true;
//                        verificarHijos(hojasAEvitar, hijos);
//                    }
//                }else{
//                    //2.1.A
//                    arbol.cargarHijosDinamico(hojaActual);
//                    hijos = hojaActual.getHijos();
//                    raizSinHijosMejores = false;
//                    verificarHijos(hojasAEvitar, hijos);
//                }
//                if(hijos.size() != 0){
//                    mejorTemp = hijos.get(0);
//                    for (Iterator<Hoja> it = hijos.iterator(); it.hasNext();) {
//                        Hoja hijo = it.next();
//                        obtenerMetrica(hijo);
//                        obtenerMetrica(hojaActual);
//                        obtenerMetrica(mejorTemp);
//                        //2.1.B
//                        if(hijo.esEstadoFinal()){
//                            optimo.add(hijo);
//                            fin = true;
//                            break;
//                        }
//                        //2.1.B
//                        if(hijo.getEstado().getMetrica() < mejorTemp.getEstado().getMetrica()){
//                            mejorTemp = hijo;
//                        }
//                    }//end for
//                    if(fin){
//                        break;
//                    }
//                    //2.1.C.
//                    if(mejorTemp.getEstado().getMetrica() <= hojaActual.getEstado().getMetrica()){
//                        tieneHijosMejores = true;
//                        optimo.add(hojaActual);
//                        hojaActual = mejorTemp;
//                    }else{
//                        System.out.println("Hoja actual tiene mejor heurística que sus hijos --> " + hojaActual.toString());
//                        //si es el raiz si o si selecciono al mejor hijo (aunque no tenga mejor heuristica)
//                        if(raizSinHijosMejores){
//                            hojaActual = mejorTemp;
//                        }
//                        tieneHijosMejores = false;
//    //                    break;
//                    }
//                }
//                else{
//                    System.out.println("Hoja actual sin hijos.");
//                    if(hojaActual.getPadre() == null){
//                        JOptionPane.showMessageDialog(null, "El algorítmo no encontró la solución.");
//                        optimo = new ArrayList<Hoja>();
//                        optimo.add(hojaActual);
//                        break;
//                    }
//                    tieneHijosMejores = false;
////                    break;
//                }
//            }//end while
//        }//end else
//        arbol.setCaminoOptimo(optimo);
//    }
//
//    private List<Hoja> verificarHijos(List<Hoja> hojasAEvitar, List<Hoja> hijos){
//        for (Iterator<Hoja> it = hojasAEvitar.iterator(); it.hasNext();) {
//            Hoja hoja = it.next();
//            if(hijos.contains(hoja)){
//                hijos.remove(hoja);
//            }
//        }
//        return hojasAEvitar;
//    }

    @Override
    public String toString() {
        return "Escalada por máxima pendiente (propuesta)";
    }

    @Override
    public void obtenerMetrica(Hoja estado) {
        estado.getEstado().calcularMetrica(estadoFinal);
    }
}